package com.qqt.csr.order.service.statemachine.action;

import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.cola.statemachine.Action;
import com.qqt.csr.common.utils.TransactionUtil;
import com.qqt.csr.order.entity.WorkOrder;
import com.qqt.csr.order.enums.WorkOrderEventEnum;
import com.qqt.csr.order.enums.WorkOrderStatusEnum;
import com.qqt.csr.order.service.WorkOrderEventService;
import com.qqt.csr.order.service.WorkOrderService;
import com.qqt.csr.order.service.statemachine.context.WorkOrderContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @author
 */
@Slf4j
@Component
public class DefaultWorkOrderAction implements Action<WorkOrderStatusEnum, WorkOrderEventEnum, WorkOrderContext> {
    @Autowired
    protected WorkOrderService workOrderService;
    @Autowired
    protected WorkOrderEventService workOrderEventService;
    @Autowired
    protected TransactionUtil transactionUtil;
    @Autowired(required = false)
    private List<IActionPreProcessor> actionPreProcessorList;
    @Autowired(required = false)
    private List<ISubAction> subActionList;
    @Autowired(required = false)
    private List<IActionPostProcessor> actionPostProcessorList;

    @Override
    public void execute(WorkOrderStatusEnum from, WorkOrderStatusEnum to, WorkOrderEventEnum event, WorkOrderContext context) {
        log.info("开始执行工单处理逻辑，from:{},to:{},event:{},context:{}", from, to, event, context);
        WorkOrder fromOrder = context.getFromOrder();
        WorkOrder toOrder = context.getToOrder();
        toOrder.setStatus(to.getStatus());

        preExecute(from, to, event, context);
        WorkOrderStatusEnum newTo = WorkOrderStatusEnum.getByStatus(toOrder.getStatus());

        transactionUtil.execute(() -> {
            if (fromOrder == null) {
                workOrderService.insert(toOrder);
            } else {
                toOrder.setId(Optional.ofNullable(toOrder.getId()).orElse(fromOrder.getId()));
                workOrderService.update(toOrder);
            }
            workOrderEventService.insert(context);

            doExecute(from, newTo, event, context);
        });

        postExecute(from, newTo, event, context);
        log.info("结束执行工单处理逻辑,newTo:{},toOrder:{}", newTo, context.getToOrder());
    }

    /**
     * 执行工单事务之前，进行提取的操作
     *
     * @param from
     * @param to
     * @param event
     * @param context
     */
    private void preExecute(WorkOrderStatusEnum from, WorkOrderStatusEnum to, WorkOrderEventEnum event, WorkOrderContext context) {
        if (CollectionUtils.isEmpty(actionPreProcessorList)) {
            return;
        }
        actionPreProcessorList.forEach(actionPreProcessor -> {
            if (actionPreProcessor.matches(event)) {
                log.info("执行工单预处理动作:{}", actionPreProcessor.getClass());
                actionPreProcessor.preProcess(from, to, event, context);
            }
        });
    }

    /**
     * 需要和工单事务一起执行的操作
     *
     * @param from
     * @param to
     * @param event
     * @param context
     */
    private void doExecute(WorkOrderStatusEnum from, WorkOrderStatusEnum to, WorkOrderEventEnum event, WorkOrderContext context) {
        if (CollectionUtils.isEmpty(subActionList)) {
            return;
        }
        subActionList.forEach(action -> {
            if(action.matches(event)){
                log.info("执行工单子处理动作:{}", action.getClass());
                action.doExecute(from, to, event, context);
            }
        });
    }

    /**
     * 执行完工单事务之后的后续操作
     *
     * @param from
     * @param to
     * @param event
     * @param context
     */
    private void postExecute(WorkOrderStatusEnum from, WorkOrderStatusEnum to, WorkOrderEventEnum event, WorkOrderContext context) {
        if (CollectionUtils.isEmpty(actionPostProcessorList)) {
            return;
        }
        actionPostProcessorList.forEach(actionPostProcessor -> {
            if (actionPostProcessor.matches(event)) {
                log.info("执行工单后续处理动作:{}", actionPostProcessor.getClass());
                actionPostProcessor.postProcess(from, to, event, context);
            }
        });
    }
}
